home *** CD-ROM | disk | FTP | other *** search
- /*++
-
- Copyright (c) 1995 Intel Corp
-
- Module Name:
-
- chatsock.c
-
- Abstract:
-
- Socket-related functions for the WinSock2 Chat sample application.
- --*/
-
- #include "nowarn.h" /* turn off benign warnings */
- #ifndef _WINSOCKAPI_
- #define _WINSOCKAPI_ /* Prevent inclusion of winsock.h in windows.h */
- #endif
- #include <windows.h>
- #include <winsock2.h>
- #include "nowarn.h" /* some warnings may have been turned back on */
- #include <stdlib.h>
- #include <malloc.h>
- #include <stdio.h>
- #include <assert.h>
- #include <ws2atm.h>
- #include "ws2chat.h"
- #include "chatsock.h"
- #include "chatdlg.h"
-
-
-
- //
- // Static Globals
- //
-
- // points to an array of WSAPROTOCOL_INFO structs
- static LPWSAPROTOCOL_INFO InstalledProtocols = NULL;
-
- // number of WSAPROTOCOL_INFO structs in the InstalledProtocols buffer
- static int NumProtocols = 0;
-
- // static array of sockets, one for each listening socket
- static LISTENDATA ListeningSockets[MAX_LISTENING_SOCKETS];
-
- // number of meaningful entries in ListeningSockets
- static int NumFound = 0;
-
-
-
-
- //
- // Function Prototypes -- Internal Functions
- //
-
- DWORD
- IOThreadFunc(
- IN LPVOID ParamPtr);
-
- BOOL
- HandleSocketEvent(
- IN OUT PCONNDATA ConnData);
-
- BOOL
- HandleOutputEvent(
- IN OUT PCONNDATA);
-
- BOOL
- HandleOtherEvent(
- IN DWORD WaitStatus,
- IN OUT PCONNDATA ConnData);
-
- int
- HandleEvents(
- IN PCONNDATA ConnData,
- IN LPWSANETWORKEVENTS NetworkEvents);
-
- BOOL
- FillLocalAddress(
- IN LPVOID SockAddr);
-
- int
- DoRecv(
- IN PCONNDATA ConnData);
-
- int
- DoOverlappedCallbackSend(
- IN POUTPUT_REQUEST OutReq,
- IN PCONNDATA ConnData);
-
- int
- DoOverlappedEventSend(
- IN POUTPUT_REQUEST OutReq,
- IN PCONNDATA ConnData);
-
- int
- DoSend(
- IN POUTPUT_REQUEST OutReq,
- IN PCONNDATA ConnData);
-
- void CALLBACK
- SendCompFunc(
- IN DWORD Error,
- IN DWORD BytesTransferred,
- IN LPWSAOVERLAPPED OverlappedPtr,
- IN DWORD Flags);
-
- int CALLBACK
- AcceptCondFunc(
- IN LPWSABUF CallerId,
- IN LPWSABUF CallerData,
- IN LPQOS CallerSQos,
- IN LPQOS CallerGQos,
- IN LPWSABUF CalleeId,
- OUT LPWSABUF CalleeData,
- OUT GROUP FAR *Group,
- IN DWORD CallbackData);
-
- LPWSAPROTOCOL_INFO
- GetProtoFromSocket(
- IN SOCKET Socket);
-
- BOOL
- GetMaxMsgSize(
- IN OUT PCONNDATA ConnData);
-
-
-
-
- //
- // Function Definitions
- //
-
-
- BOOL
- InitWS2(void)
- /*++
-
- Routine Description:
-
- Calls WSAStartup, makes sure we have a good version of WinSock2
-
- Arguments:
-
- None.
-
- Return Value:
-
- TRUE - WinSock 2 DLL successfully started up
-
- FALSE - Error starting up WinSock 2 DLL.
-
- --*/
-
- {
- int Error; // catches return value of WSAStartup
- WORD VersionRequested; // passed to WSAStartup
- WSADATA WsaData; // receives data from WSAStartup
- BOOL ReturnValue = TRUE; // return value
-
- // Start WinSock 2. If it fails, we don't need to call
- // WSACleanup().
- VersionRequested = MAKEWORD(VERSION_MAJOR, VERSION_MINOR);
- Error = WSAStartup(VersionRequested, &WsaData);
- if (Error) {
- MessageBox(GlobalFrameWindow,
- "Could not find high enough version of WinSock",
- "Error", MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
- ReturnValue = FALSE;
- } else {
-
- // Now confirm that the WinSock 2 DLL supports the exact version
- // we want. If not, make sure to call WSACleanup().
- if (LOBYTE(WsaData.wVersion) != VERSION_MAJOR ||
- HIBYTE(WsaData.wVersion) != VERSION_MINOR) {
- MessageBox(GlobalFrameWindow,
- "Could not find the correct version of WinSock",
- "Error", MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
- WSACleanup();
- ReturnValue = FALSE;
- }
- }
- return(ReturnValue);
-
- } // InitWS2()
-
-
-
-
-
- BOOL
- FindProtocols(void)
- /*++
-
- Routine Description:
-
- Finds out about all transport protocols installed on the local
- machine and saves the information into global variables.
-
- Implementation:
-
- This function uses WSAEnumProtocols to find out about all
- installed protocols on the local machine. It stores this
- information in two variables which are global to this file;
- InstalledProtocols is a pointer to a buffer of WSAPROTOCOL_INFO
- structs, while NumProtocols is the number of protocols in that
- buffer. This function is the only function in the file allowed to
- touch these variables.
-
- Arguments:
-
- None.
-
- Return Value:
-
- TRUE - Successfully initialized the protocol buffer.
-
- FALSE - Some kind of problem arose. The user is informed of the
- error.
-
- --*/
- {
-
- DWORD BufferSize = 0; // size of InstalledProtocols buffer
- char MsgText[MSG_LEN]; // holds message strings
-
-
- // Call WSAEnumProtocols to figure out how big of a buffer we need.
- NumProtocols = WSAEnumProtocols(NULL,
- NULL,
- &BufferSize);
-
- if ((NumProtocols != SOCKET_ERROR) && (WSAGetLastError() != WSAENOBUFS)) {
- // We're in trouble!!
- MessageBox(GlobalFrameWindow, "WSAEnumProtocols is broken.", "Error",
- MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
- goto Fail;
- }
-
- // Allocate a buffer, call WSAEnumProtocols to get an array of
- // WSAPROTOCOL_INFO structs.
- InstalledProtocols = (LPWSAPROTOCOL_INFO)malloc(BufferSize);
- if (InstalledProtocols == NULL) {
- MessageBox(GlobalFrameWindow, "malloc failed.", "Error",
- MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
- goto Fail;
- }
- NumProtocols = WSAEnumProtocols(NULL,
- (LPVOID)InstalledProtocols,
- &BufferSize);
- if (NumProtocols == SOCKET_ERROR) {
- // uh-oh
- wsprintf(MsgText, "WSAEnumProtocols failed. Error Code: %d",
- WSAGetLastError());
- MessageBox(GlobalFrameWindow, MsgText, "Error",
- MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
- goto Fail;
- }
- return(TRUE);
-
- Fail:
-
- WSACleanup();
- return(FALSE);
-
- } // FindProtocols()
-
-
-
-
-
- BOOL
- FillLocalAddress(
- IN struct sockaddr *pSockAddr)
- /*++
-
- Routine Description:
-
- Fills in the struct sockaddr with a local address appropriate for
- the address family, for use in a call to bind.
-
- Arguments:
-
- SockAddr -- A pointer to a struct sockaddr which will be filled in
- appropriately, as determined by the particular address family.
- The address family field (sa_family) must already be filled into
- the structure before being passed into this function.
-
- Return Value:
-
- TRUE -- FillLocalAddress recognized the address family and
- successfully filled in the struct sockaddr. This structure is
- ready to be passed to a bind() call.
-
- FALSE -- FillLocalAddress didn't recognize the address family and
- didn't touch the struct sockaddr.
-
- --*/
- {
-
- struct sockaddr_in *pInetSockAddr; // used to cast SockAddr to an INET address
- struct sockaddr_atm *pATMSockAddr; // used to cast SockAddr to an ATM address
- BOOL ReturnValue = TRUE; // holds the return value
-
- switch (pSockAddr->sa_family) {
-
- case AF_INET:
-
- // Cast the pointer so we can now access it's fields as a
- // struct sockaddr_in, the address structure for internet
- // addresses.
- pInetSockAddr = (struct sockaddr_in *)pSockAddr;
- if (!DialogBoxParam(GlobalInstance,
- "InetListenPortDlg",
- GlobalFrameWindow,
- InetListenPortDlgProc,
- (LPARAM)pInetSockAddr)) {
- ReturnValue = FALSE;
- }
- break;
-
- case AF_ATM:
- pATMSockAddr = (struct sockaddr_atm *)pSockAddr;
-
- pATMSockAddr->satm_number.AddressType = SAP_FIELD_ANY;
- pATMSockAddr->satm_blli.Layer2Protocol = SAP_FIELD_ANY;
- pATMSockAddr->satm_blli.Layer3Protocol = SAP_FIELD_ANY;
- pATMSockAddr->satm_bhli.HighLayerInfoType = BHLI_UserSpecific;
-
- ReturnValue = DialogBoxParam(GlobalInstance,
- "ATMSOCKADDRDLG",
- GlobalFrameWindow,
- (DLGPROC)ATMSockAddrProc,
- (LPARAM)pATMSockAddr);
- break;
-
- default:
-
- ReturnValue = FALSE;
- break;
- }
- return(ReturnValue);
-
- } // FillLocalAddress()
-
-
-
-
-
- BOOL
- ListenAll(void)
-
- /*++
-
- Routine Description:
-
- For each installed, connection-oriented protocol, this function
- creates a socket, binds to a local address, and listens on the
- created socket. The socket is set up for Windows message
- notification for any connection attempts.
-
- Arguments:
-
- None.
-
- Return Value:
-
- TRUE - Successfully listened on all installed protocols.
-
- FALSE - Error listening on all installed protocols. It is not an
- error if there are more connection-oriented protocols than
- MAX_LISTENING_SOCKETS installed; in this case we just ignore any
- extra protocols.
-
- --*/
-
- {
- struct sockaddr *SockAddr; // holds socket addresses
- int SockAddrLen; // length, in bytes, of SockAddrLen
- LPWSAPROTOCOL_INFO COProtocolInfo; // current protocol info to examine
- int i; // counting variable
- char MsgText[MSG_LEN]; // holds message strings
- int Error; // holds return values
- int Index; // indexes into text messages
-
-
- // Find all protocols that support connection-oriented data
- // transfer; create a socket, bind to a local address and listen
- // for connections on that socket for each such protocol found.
- // Also fill in an entry in the ListeningSockets array.
- for (i = 0; i < NumProtocols; i++) {
-
- COProtocolInfo = &InstalledProtocols[i];
- assert(COProtocolInfo != NULL);
- if (UseProtocol(COProtocolInfo)) {
-
- // We've found a suitable protocol. Create a socket, fill
- // in the next entry in ListeningSockets
- ListeningSockets[NumFound].Socket = WSASocket(FROM_PROTOCOL_INFO,
- FROM_PROTOCOL_INFO,
- FROM_PROTOCOL_INFO,
- COProtocolInfo,
- 0,
- WSA_FLAG_OVERLAPPED);
- if (ListeningSockets[NumFound].Socket == INVALID_SOCKET) {
- UCHAR textBuf[MAX_ERROR_TEXT];
- sprintf(textBuf, "Could not open a socket. [%x]", WSAGetLastError());
- MessageBox(GlobalFrameWindow, textBuf,
- "Non-fatal error.",
- MB_OK | MB_SETFOREGROUND);
- continue;
- }
- ListeningSockets[NumFound].ProtocolInfo = COProtocolInfo;
-
- // Allocate a block of memory for the socket address and
- // zero it out.
- SockAddrLen = COProtocolInfo->iMaxSockAddr;
- SockAddr = (struct sockaddr *)malloc(SockAddrLen);
-
- if (!SockAddr) {
- ChatSysError("malloc()",
- "ListenAll()",
- TRUE);
- }
- memset((char *)SockAddr, 0, SockAddrLen);
-
- // Get a local address to bind the socket to
- SockAddr->sa_family = (u_short)COProtocolInfo->iAddressFamily;
- FillLocalAddress(SockAddr);
-
- // Bind the socket to SockAddr.
- Error = bind(ListeningSockets[NumFound].Socket,
- SockAddr,
- SockAddrLen);
- if (Error == SOCKET_ERROR) {
- // bind() failed
- UCHAR textBuf[MAX_ERROR_TEXT];
- sprintf(textBuf, "Could not bind the socket. [%x]", WSAGetLastError());
- MessageBox(GlobalFrameWindow, textBuf,
- "Non-fatal error", MB_OK | MB_SETFOREGROUND);
- free(SockAddr);
- continue;
- }
-
- free(SockAddr);
-
- // Set up the socket for windows message event notification.
- // Note that this call automatically puts the socket into
- // non-blocking mode, as if we had called WSAIoctl with
- // the FIONBIO flag.
- Error = WSAAsyncSelect(ListeningSockets[NumFound].Socket,
- GlobalFrameWindow,
- USMSG_ACCEPT,
- FD_ACCEPT);
- if (Error == SOCKET_ERROR) {
- MessageBox(GlobalFrameWindow, "Error: WSAAsyncSelect()",
- "Non-fatal error", MB_OK | MB_SETFOREGROUND);
- continue;
- }
-
- // Listen for incoming connection requests on the socket.
- Error = listen(ListeningSockets[NumFound].Socket,
- SOMAXCONN);
- if (Error == SOCKET_ERROR) {
- MessageBox(GlobalFrameWindow, "Error: listen()",
- "Non-fatal error",
- MB_OK | MB_SETFOREGROUND);
- continue;
- }
-
- // Looks good -- increase the count, check for overflow of
- // the max amount, re-iterate if we're ok.
- if (++NumFound == MAX_LISTENING_SOCKETS) {
- wsprintf(MsgText,
- "More than %d useable protocols. Ignoring extras.",
- MAX_LISTENING_SOCKETS);
- MessageBox(GlobalFrameWindow, MsgText, "Alert",
- MB_OK | MB_SETFOREGROUND);
- break;
- }
-
- } // if (UseProtocol(COProtocolInfo))
- } // for(; ; ;)
-
- if (NumFound == 0) {
-
- Index = wsprintf(MsgText,
- "Couldn't find a suitable protocol ");
- Index += wsprintf(MsgText + Index,
- "and/or no listening sockets could be opened.\r\n");
- wsprintf(MsgText + Index, "Shall we continue anyway?");
-
- if (MessageBox(GlobalFrameWindow, MsgText, "No protocols.",
- MB_ICONQUESTION | MB_YESNO | MB_SETFOREGROUND)
- == IDNO) {
-
- WSACleanup();
- return(FALSE);
- }
- }
-
- return(TRUE);
-
- } // ListenAll()
-
-
-
-
-
- BOOL
- UseProtocol(
- IN LPWSAPROTOCOL_INFO Proto)
- /*++
-
- Routine Description:
-
- Returns true if Proto is suitable for use by Chat.
-
- Arguments:
-
- Proto -- Points to a protocol information struct.
-
- Return Value:
-
- TRUE -- Chat likes it.
-
- FALSE -- Get this chintzy protocol out of here!
-
- --*/
- {
-
- if (!(Proto->dwServiceFlags1 & XP1_CONNECTIONLESS) &&
- //(Proto->dwServiceFlags1 & XP1_GUARANTEED_DELIVERY) &&
- (Proto->dwServiceFlags1 & XP1_GUARANTEED_ORDER)) {
-
- return(TRUE);
-
- } else {
-
- return(FALSE);
- }
- } // UseProtocol
-
-
-
-
-
- void
- CleanUpSockets(void)
- /*++
-
- Routine Description:
-
- This function closes all listening sockets.
-
- Arguments:
-
- None.
-
- Return Value:
-
- None.
-
- --*/
- {
-
- int i; // counting variable
-
- for (i = 0; i < NumFound; i++) {
- closesocket(ListeningSockets[i].Socket);
- }
- } // CleanUpSockets()
-
-
-
-
-
- int CALLBACK
- AcceptCondFunc(
- IN LPWSABUF CallerId,
- IN LPWSABUF CallerData,
- IN LPQOS CallerSQos,
- IN LPQOS CallerGQos,
- IN LPWSABUF CalleeId,
- OUT LPWSABUF CalleeData,
- OUT GROUP FAR *Group,
- IN DWORD CallbackData)
- /*++
-
- Routine Description:
-
- Condition function called when an incoming connection request is
- handled.
-
- Implementation:
-
- This function allows the user to accept or reject an incoming
- connection request after examining the caller's name and the
- subject of the call. If the call is accepted, and
- connection-time data transfer is supported by the particular
- protocol on which the connection is made, a dialog box comes up
- which prompts the user for his/her name.
-
- Arguments:
-
- CallerId -- Supplies the address of the caller.
-
- CallerData -- Supplies the caller's user data. Chat uses this
- parameter to send the caller's name and the subject of the call.
-
- CallerSQos -- Supplies the forward and backward QOS.
-
- CallerGQos -- Supplies the forward and backward flow specs for the
- socket group the caller is to create. Not used by chat.
-
- CalleeId -- Supplies the local address.
-
- CalleeData -- Returns user data back to the caller (Chat uses this
- parameter to return the callee's name)
-
- Group -- Returns the appropriate group action to take on the
- connecting socket. Not used by chat. Always returns NULL.
-
- CallbackData -- Supplies a pointer the CONNDATA structure
- associated with this connection.
-
- Return Value:
-
- CF_ACCEPT - Accept the connection request from the caller.
-
- CF_REJECT - Reject the connection request from the caller.
-
- --*/
-
- {
- char MsgText[MSG_LEN]; // build message string here
- char TitleText[TITLE_LEN + 1]; // build title string here
- PCONNDATA ConnData; // connection-specific data
- int Index; // index into MsgText
- int ReturnValue = CF_ACCEPT; // return value
-
- ConnData = (PCONNDATA)CallbackData;
-
- // CallerId contains the socket address of the connecting entity.
- // Copy this into the connection-specific data.
- ConnData->RemoteSockAddr.len = CallerId->len;
- ConnData->RemoteSockAddr.buf = malloc(ConnData->RemoteSockAddr.len);
- if (ConnData->RemoteSockAddr.buf == NULL) {
- ChatSysError("malloc()",
- "AcceptCondFunc()",
- TRUE);
- }
- memcpy((char *)ConnData->RemoteSockAddr.buf, (char *)CallerId->buf,
- CallerId->len);
-
- // Translate the RemoteSockAddr into a human readable form, and
- // store it in ConnData->PeerAddress
- GetAddressString(ConnData->PeerAddress,
- ConnData->RemoteSockAddr.buf,
- ConnData->RemoteSockAddr.len,
- ConnData->ProtocolInfo);
-
- Index = wsprintf(MsgText, "Someone is attempting a chat connection.\r\n");
-
- if (CallerData != NULL) {
-
- // The connection request has come with some caller data. Use
- // it to inform the user of who is trying to connect
- ExtractTwoStrings(CallerData->buf,
- ConnData->PeerName,
- NAME_LEN + 1,
- ConnData->Subject,
- SUB_LEN + 1);
-
- // Build the strings for the message box and the title of the
- // connection window
- Index += wsprintf(MsgText + Index,
- "From: %s\r\nSubject: %s\r\n", ConnData->PeerName,
- ConnData->Subject);
- wsprintf(TitleText, "Connected to: %s @ %s", ConnData->PeerName,
- ConnData->PeerAddress);
-
- } else {
-
- // There is no caller data...build a string for the title.
- wsprintf(TitleText, "Connected to: %s", ConnData->PeerAddress);
- }
-
- // Continue building MsgText.
- Index += wsprintf(MsgText + Index, "Address: %s\r\n",
- ConnData->PeerAddress);
- Index += wsprintf(MsgText + Index, "Would you like to accept it?");
-
- // Prompt the user to accept or reject the connection.
- //
- // ****NOTE****
- // This is NOT the right way to do this. The application should
- // not hold up this thread by putting up this message box, or the
- // dialog box below. As mentioned in the API spec, this function
- // should return "as soon as possible", and clearly this is not
- // what's being done here. Please look to future versions of chat
- // for a fix. Thanks.
- if (MessageBox(ConnData->ConnectionWindow, MsgText,
- "Connection Request",
- MB_ICONQUESTION | MB_YESNO | MB_SETFOREGROUND) == IDYES) {
-
- // The user has accepted the connection request.
- SetWindowText(ConnData->ConnectionWindow, TitleText);
- if (CalleeData != NULL) {
-
- // We can try to pass user data back. Call up a dialog box
- // to get a name string and put it into CalleeData.
- if (!DialogBoxParam(GlobalInstance,
- "AcceptConnectionDlg",
- ConnData->ConnectionWindow,
- AcceptConnectionDlgProc,
- (LPARAM)CalleeData)) {
-
- CalleeData->len = 0;
- }
- }
- ReturnValue = CF_ACCEPT;
-
- } // if (MessageBox(...))
- else {
-
- // The user has rejected the connection request.
- ReturnValue = CF_REJECT;
- }
- return(ReturnValue);
-
- } // AcceptCondFunc()
-
-
-
-
-
- BOOL
- GetAddressString(
- OUT char *String,
- IN LPVOID SockAddr,
- IN int SockAddrLen,
- IN LPWSAPROTOCOL_INFO ProtocolInfo)
- /*++
-
- Routine Description:
-
- This function translates the SockAddr into a human-readable
- string, if possible. If chat doesn't recognize the protocol, then
- the string "(unknown)" is returned in String.
-
- Arguments:
-
- String -- Returns the string representing the SockAddr in a
- human-readable form.
-
- SockAddr -- An address.
-
- SockAddrLen -- The length, in bytes, of SockAddr.
-
- ProtocolInfo -- Pointer to the protocol information structure.
-
- Return Value:
-
- TRUE -- Chat recognized the protocol family and successfully
- translated the address.
-
- FALSE -- Chat did not recognize the protocol family and returned
- the string "(unknown)".
-
- --*/
- {
-
- char *TempString; // string returned by inet_ntoa
- struct sockaddr_in *SockAddrInet; // casts the address to a sockaddr_in
- BOOL ReturnValue; // holds the return value
-
- ReturnValue = TRUE;
-
- switch (ProtocolInfo->iAddressFamily) {
-
- case AF_INET:
-
- // It's an Internet-style address.
- SockAddrInet = (struct sockaddr_in *)SockAddr;
- TempString = inet_ntoa(SockAddrInet->sin_addr);
- if (TempString == NULL) {
- MessageBox(NULL, "inet_ntoa() failed.", "Error.",
- MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
- } else {
- strcpy(String, TempString);
- }
- ReturnValue = TRUE;
- break;
-
- default:
-
- strcpy(String, "(unknown)");
- ReturnValue = FALSE;
- break;
- }
- return(ReturnValue);
-
- } // GetAddressString()
-
-
-
-
-
- int
- HandleEvents(
- IN PCONNDATA ConnData,
- IN LPWSANETWORKEVENTS NetworkEvents)
-
- /*++
-
- Routine Description:
-
- Handles network events that may occur on a connected socket.
- The events handled by this function are FD_CLOSE, FD_READ, and
- FD_WRITE.
-
- Arguments:
-
- ConnData - Supplies a pointer to data for the connection on which
- the event happened.
-
- NetworkEvents - Supplies a WSANETWORKEVENT structure, which is a
- record of the network events that have occurred as well as any
- accompanying error-codes.
-
- Return Value:
-
- CHAT_OK -- The network event was successfully handled.
-
- CHAT_ERROR -- Some kind of error occurred while handling the
- event, and the connection should be closed.
-
- CHAT_CLOSED -- The connection has been gracefully closed.
-
- --*/
-
- {
- int Result; // holds the result of DoRecv
- int ReturnValue = CHAT_OK; // return value
-
- // The following three if statements all execute unless one gets
- // an error or closed socket, in which case we return immediately.
- if (NetworkEvents->lNetworkEvents & FD_READ) {
-
- // An FD_READ event has occurred on the connected socket.
- if (NetworkEvents->iErrorCode[FD_READ_BIT] == WSAENETDOWN) {
-
- // There is an error.
- ReturnValue = CHAT_ERROR;
- goto Done;
-
- } else {
-
- // Read data off the socket...
- Result = DoRecv(ConnData);
- if ((Result == CHAT_ERROR) || (Result == CHAT_CLOSED)) {
- ReturnValue = Result;
- goto Done;
- }
- }
- }
-
- if (NetworkEvents->lNetworkEvents & FD_WRITE) {
-
- // An FD_WRITE event has occurred on the connected socket.
- if (NetworkEvents->iErrorCode[FD_WRITE_BIT] == WSAENETDOWN) {
-
- // There is an error.
- ReturnValue = CHAT_ERROR;
- goto Done;
-
- } else {
-
- // Allow chat to send on this socket, and signal the
- // OuputEventObject in case there is pending output that is
- // not completed due to WSAEWOULDBLOCK.
- ConnData->WriteOk = TRUE;
- SetEvent(ConnData->OutputEventObject);
- }
- }
-
- if (NetworkEvents->lNetworkEvents & FD_CLOSE) {
-
- if (NetworkEvents->iErrorCode[FD_CLOSE_BIT] == 0) {
-
- // A graceful shutdown has occurred...
- ReturnValue = CHAT_CLOSED;
- goto Done;
-
- } else {
-
- // This is some other type of abortive close or failure...
- ReturnValue = CHAT_ABORTED;
- goto Done;
- }
-
- }
-
- Done:
- return(ReturnValue);
-
- } // HandleEvents()
-
-
-
-
-
- DWORD
- IOThreadFunc(
- IN LPVOID ParamPtr)
-
- /*++
-
- Routine Description:
-
- This routine is invoked as a separate thread to handle all input
- and output for a connection.
-
- Implementation:
-
- This thread sits in a loop, waiting for one of several things to
- occur. These can be:
-
- 1. The user interface thread has some input ready to be sent,
- and has signaled the ouput event object.
-
- 2. WinSock 2 has indicated there is a network event associated
- with the socket.
-
- 3. Callback notification. This can be via an event or via a
- queued callback function, depending on whether or not we've
- compiled with the CALLBACK_NOTIFICATION flag.
-
- The return value from the wait indicates what has
- happened, and a switch statement handles all the possible cases.
- When there is an error or the connection is being closed, the loop
- is broken and the thread will exit and the connection window will
- be closed (and sent a WM_DESTROY message).
-
- Arguments:
-
- ParamPtr - Supplies a pointer to a ConnData structure that holds
- data specific to this connection.
-
- Return Value:
-
- 0 - Always returns 0. The return value is not needed.
-
- --*/
- {
- char MsgText[MSG_LEN]; // holds message strings
- DWORD WaitStatus; // holds return value of the wait
- PCONNDATA ConnData; // connection-specific data
- BOOL KeepGoing = TRUE; // keep processing output requests?
- BOOL Forever = TRUE; // constant to avoid warning
-
- ConnData = (PCONNDATA)ParamPtr;
-
- // Initialize the EventArray. The only two events in it, for now,
- // are the Socket and Ouput events; if this is the event
- // notification version of chat, then there will be an additional
- // event for each overlapped send waiting for a completion
- // notification.
- ConnData->NumEvents = 2;
- ConnData->EventArray[0] = ConnData->SocketEventObject;
- ConnData->EventArray[1] = ConnData->OutputEventObject;
-
- // Initialize the array of output requests, which is indexed in
- // parallel to the above event array. When an event is signaled,
- // we can figure out which output request and overlapped
- // structures to free by indexing into this array.
- // These first two entries should never be referenced, because
- // their parallel entries in EventArray (see above) are for the
- // permanent Socket and Output event objects.
- ConnData->OutReqArray[0] = ConnData->OutReqArray[1] = NULL;
-
- while (Forever) {
-
- // Wait for an event (or a queued callback function) to wake
- // us up. This is an alertable wait state (fAlertable == TRUE).
- WaitStatus = WSAWaitForMultipleEvents(ConnData->NumEvents,
- ConnData->EventArray,
- FALSE, // fWaitAll
- WSA_INFINITE, // dwTimeout
- TRUE); // fAlertable
-
- // Determine why we woke up and act accordingly. Note that
- // breaking out of the switch causes us to break out of the
- // while loop as well. When we don't want to break out of the
- // loop, case statements end with the continue statement.
- switch (WaitStatus) {
-
- case WSA_WAIT_FAILED:
-
- // A fatal error. Pop up a message box and break out of
- // the while loop to end the thread.
-
- wsprintf(MsgText,
- "WSAWaitForMultipleEvents() failed. Error code: %d",
- WSAGetLastError());
- MessageBox(ConnData->ConnectionWindow, MsgText, "Fatal Error",
- MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
- break;
-
- case WAIT_IO_COMPLETION:
-
- // An I/O completion routine has been executed. Cleanup
- // has already occurred in SendCompFunc, so there is
- // nothing left to do. Just reiterate through the loop.
-
- continue;
-
- case WSA_WAIT_EVENT_0:
-
- // The SocketEventObject has been signaled. Handle it in
- // a separate function. Break out of the thread if
- // HandleSocketEvent returns FALSE, indicating error.
- if (HandleSocketEvent(ConnData)) {
- continue;
- } else {
- break;
- }
-
- // Please note: WSA_WAIT_EVENT_[1,2,3] are defined in
- // chatsock.h, not winsock2.h like WSA_WAIT_EVENT_0
-
- case WSA_WAIT_EVENT_1:
-
- // The OuputEventObject has been signaled. Handle it in a
- // separate function, and break out of the thread if it
- // returns FALSE
- if (HandleOutputEvent(ConnData)) {
- continue;
- } else {
- break;
- }
-
- default:
-
- // Some other event has been signaled. Handle it in a
- // separate function, and break out of the thread if it
- // returns FALSE.
- if (HandleOtherEvent(WaitStatus, ConnData)) {
- continue;
- } else {
- break;
- }
-
- } // switch (WaitStatus)
-
- // Break out of the while loop.
- break;
-
- } // while (1)
-
- // Thread is ending because the connection was closed or an error
- // occurred
- PostMessage(ConnData->ConnectionWindow,
- WM_CLOSE,
- 0,
- 0);
- return(0);
-
- } // IOThreadFunc()
-
-
-
-
-
- BOOL
- HandleSocketEvent(
- IN OUT PCONNDATA ConnData)
- /*++
-
- Routine Description:
-
- Handles the case in IOThreadFunc where the thread is woken up by a
- signal to the socket event object.
-
- Arguments:
-
- ConnData - Supplies a pointer to data for the connection on which
- the event happened.
-
- Return Value:
-
- TRUE -- Chat successfully handled the event and the thread should
- continue on.
-
- FALSE -- An error occurred and Chat should kill the thread and the
- connection.
-
- --*/
- {
- int Result; // holds return values
- WSANETWORKEVENTS NetworkEvents; // tells us what events happened
- char MsgText[MSG_LEN]; // holds text strings
- BOOL ReturnValue; // holds the return value
-
- // Find out what happened and act accordingly.
- Result = WSAEnumNetworkEvents(ConnData->Socket,
- ConnData->SocketEventObject,
- &NetworkEvents);
- if (Result == SOCKET_ERROR) {
-
- // Handle the fatal error.
- wsprintf(MsgText,
- "WSAEnumNetworkEvents failed. Error code: %d",
- Result);
- MessageBox(GlobalFrameWindow, MsgText, "Fatal Error",
- MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
- ReturnValue = FALSE;
-
- } else {
-
- // Handle all of the network events on the given socket
- Result = HandleEvents(ConnData, &NetworkEvents);
-
- if (Result == CHAT_CLOSED) {
-
- // HandleEvents() has determined that the remote party
- // has terminated the connection. Inform the user, and
- // return.
- if (ConnData->PeerName[0] != 0) {
- wsprintf(MsgText,
- "%s @ %s has terminated the connection.",
- ConnData->PeerName, ConnData->PeerAddress);
- } else {
- wsprintf(MsgText,
- "The party at %s has terminated the connection.",
- ConnData->PeerAddress);
- }
- MessageBox(ConnData->ConnectionWindow, MsgText, "Sorry!",
- MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
- ReturnValue = FALSE;
-
- } else if (Result == CHAT_ABORTED) {
-
- // HandleEvents has determined that the connection has
- // been aborted due to an undetermined error.
- MessageBox(ConnData->ConnectionWindow,
- "The connection has been broken.",
- "Connection aborted.",
- MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
- ReturnValue = FALSE;
-
- } else if (Result == CHAT_ERROR) {
-
- // HandleEvents() has returned an error. Inform the
- // user and break to exit the thread and kill the window.
- MessageBox(ConnData->ConnectionWindow,
- "An unidentified network or system error occurred.",
- "Error.", MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
- ReturnValue = FALSE;
-
- } else if (Result == CHAT_OK) {
-
- // Inform the caller that everything went fine.
- ReturnValue = TRUE;
-
-
- } else {
-
- // This case should only occur if there is a
- // programming error. Break out of the while loop to
- // kill the thread, the window, and therefore the
- // connection.
- MessageBox(ConnData->ConnectionWindow,
- "HandleEvents() returned an unexpected value.",
- "Error.", MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
- ReturnValue = FALSE;
- }
- }
-
- return(ReturnValue);
-
- } // HandleSocketEvent()
-
-
-
-
-
- BOOL
- HandleOutputEvent(
- IN OUT PCONNDATA ConnData)
- /*++
-
- Routine Description:
-
- Handles the case in IOThreadFunc where the thread is woken up by a
- signal to the output event object.
-
- Arguments:
-
- ConnData - Supplies a pointer to data for the connection on which
- the event happened.
-
- Return Value:
-
- TRUE -- Chat successfully handled the event and the thread should
- continue on.
-
- FALSE -- An error occurred and Chat should kill the thread and the
- connection.
-
- --*/
- {
- BOOL ReturnValue; // holds the return value
- BOOL KeepGoing; // keep pulling requests off the queue?
- POUTPUT_REQUEST OutReq; // pointer to the output request
- int Result; // holds results of functions
-
- ReturnValue = TRUE;
-
- // First we check to see if a previous send attempt failed with
- // WSAEWOULDBLOCK; if so, we don't have to bother trying to send
- // data until we get an FD_WRITE network event, so just return
- // with TRUE to indicate that the thread should wait again.
- if (ConnData->WriteOk) {
-
- // This loop pulls output requests off the queue and hands
- // them to DoSend.
- KeepGoing = TRUE;
- while (KeepGoing) {
-
- OutReq = (POUTPUT_REQUEST)QRemove(ConnData->OutputQueue);
- if (OutReq == NULL) {
-
- // Nothing is left on the queue.
- KeepGoing = FALSE;
- ReturnValue = TRUE;
-
- } else {
-
- // Do the output
- Result = DoSend(OutReq, ConnData);
- if (Result == CHAT_WOULD_BLOCK) {
-
- // The send would have blocked; we need to
- // requeue the output request and wait for an
- // FD_WRITE network event.
- KeepGoing = FALSE;
- QInsertAtHead(ConnData->OutputQueue, (LPVOID)OutReq);
- ReturnValue = TRUE;
-
- } else if (Result == CHAT_ERROR) {
-
- // An error occurred in DoSend. Set KeepGoing to
- // FALSE in order to get us out of the loop.
- KeepGoing = FALSE;
- ReturnValue = FALSE;
- MessageBox(ConnData->ConnectionWindow,
- "Error sending data.",
- "Error.",
- MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
-
- } else {
-
- // DoSend returned CHAT_OK. Keep looping.
- continue;
- }
- }
- } // while (KeepGoing)
- } // if (ConnData->WriteOk)
-
- return(ReturnValue);
-
- } // HandleOutputEvent()
-
-
-
-
-
- BOOL
- HandleOtherEvent(
- IN DWORD WaitStatus,
- IN OUT PCONNDATA ConnData)
- /*++
-
- Routine Description:
-
- Handles the case in IOThreadFunc where the thread is woken up by
- an event that is either an overlapped I/O event or was not
- specified in the event array (which is an error!).
-
- Arguments:
-
- WaitStatus -- Supplies the value returned by
- WSAWaitForMultipleEvents.
-
- ConnData - Supplies a pointer to data for the connection on which
- the event happened.
-
- Return Value:
-
- TRUE -- Chat successfully handled the event and the thread should
- continue on.
-
- FALSE -- An error occurred and Chat should kill the thread and the
- connection.
-
- --*/
- {
- POUTPUT_REQUEST OutReq; // points to an output request
- BOOL ReturnValue; // holds the return value
- DWORD Count; // counting variable
- char MsgText[MSG_LEN]; // holds message strings
-
- // First do a sanity check to make sure the index returned is
- // within the bounds of what WE think is the event array.
- if ((WaitStatus >= WSA_WAIT_EVENT_0) &&
- (WaitStatus <= (WSA_WAIT_EVENT_0 + ConnData->NumEvents - 1))) {
-
- // Free the data buffer, the overlapped structure, the output
- // request itself, and the event
- OutReq = ConnData->OutReqArray[WaitStatus - WSA_WAIT_EVENT_0];
- free(OutReq->Buffer.buf);
- free(OutReq->Overlapped);
- free(OutReq);
-
- CloseHandle(ConnData->EventArray[WaitStatus - WSA_WAIT_EVENT_0]);
-
- // Update all our event and output request arrays to
- // reflect that the overlapped send has completed.
- ConnData->NumEvents--;
- for (Count = (WaitStatus - WSA_WAIT_EVENT_0);
- Count < ConnData->NumEvents;
- Count++) {
- ConnData->EventArray[Count] = ConnData->EventArray[Count + 1];
- ConnData->OutReqArray[Count] = ConnData->OutReqArray[Count + 1];
- }
- ReturnValue = TRUE;
-
- } else {
-
- // WSAWaitForMultipleEvents returned an unexpected
- // value...
- wsprintf(MsgText, "WSAWaitForMultipleEvents() returned %d.",
- WaitStatus);
- MessageBox(GlobalFrameWindow, MsgText, "Error.",
- MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
- ReturnValue = FALSE;
- }
-
- return(ReturnValue);
-
- } // HandleOtherEvent()
-
-
-
-
-
- void
- HandleAcceptMessage(
- IN HWND ConnectionWindow,
- IN SOCKET Socket,
- IN LPARAM LParam)
- /*++
-
- Routine Description:
-
- Handles the reception of a USMSG_ACCEPT message, which indicates a
- connection attempt is incoming.
-
- Implementation:
-
- This function lets the user decide whether to accept the
- connection; if he or she does, the function initializes
- connection-specific data, calls WSAEventSelect to register
- interest in certain network events, and starts a network event
- handling thread.
-
- Arguments:
-
- ConnectionWindow -- Handle to the connection window associated
- with this connection request.
-
- Socket -- Contains the handle to the listening socket to which the
- connection request has been made.
-
- LParam -- The LParam that was delivered with the USMSG_ACCEPT
- message; contains the error code.
-
- Return Value:
-
- None.
-
- --*/
- {
-
- int Error; // gets error code if necessary
- char MsgText[MSG_LEN]; // holds message strings
- DWORD ThreadId; // needed for CreateThread
- PCONNDATA ConnData; // connection-specific data
-
- ConnData = GetConnData(ConnectionWindow);
-
- Error = WSAGETSELECTERROR(LParam);
-
- // Check to see if there was an error on the connection attempt.
- if (Error) {
-
- // Some kind of error occurred.
- if (Error == WSAENETDOWN) {
- MessageBox(ConnectionWindow,
- "The network is down!", "Uh-oh",
- MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
- } else {
- MessageBox(ConnectionWindow,
- "Unknown error on FD_ACCEPT", "Error",
- MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
- }
- goto Fail;
- }
-
- // Get a pointer to the associated protocol information structure
- // for the socket we are listening on (Socket). This will be the
- // same as the protocol info for the new socket. Note that we
- // could have allocated a new buffer and called getsockopt with
- // the SO_PROTOCOL_INFO option. But since we've already allocated
- // the memory, this way is more efficient.
- ConnData->ProtocolInfo = GetProtoFromSocket(Socket);
- assert(ConnData->ProtocolInfo != NULL);
-
- // Accept the connection (this calls AcceptCondFunc, of course,
- // before actually accepting the connection).
- {
- struct sockaddr address;
- int address_len;
-
- address_len = sizeof (address);
- ConnData->Socket = WSAAccept(Socket,
- &address,
- &address_len,
- NULL,
- (DWORD)NULL);
- // ConnData->Socket = WSAAccept(Socket,
- // NULL,
- // NULL,
- // AcceptCondFunc,
- // (DWORD)ConnData);
- }
-
- if (ConnData->Socket == INVALID_SOCKET) {
-
- // WSAAccept failed -- inform the user and that's all.
- Error = WSAGetLastError();
- if (Error != WSAECONNREFUSED) {
-
- // An unexpected error code.
- wsprintf(MsgText, "WSAAccept failed. Error code: %d",
- Error);
- MessageBox(ConnectionWindow, MsgText, "Error",
- MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
- goto Fail;
-
- } else {
-
- // AcceptCondFunc returned CF_REJECT...
- MessageBox(GlobalFrameWindow,
- "The connection attempt has been refused.",
- "Connection refused.", MB_OK | MB_SETFOREGROUND);
- goto Fail;
- }
- }
-
- WSAAsyncSelect(ConnData->Socket,
- GlobalFrameWindow,
- 0,
- 0);
-
- // Put Connection in Event Object Notification Mode.
- WSAEventSelect(ConnData->Socket,
- ConnData->SocketEventObject,
- FD_READ | FD_WRITE | FD_CLOSE);
-
- // Determine the maximum message size, if any.
- if (!GetMaxMsgSize(ConnData)) {
- goto Fail;
- }
-
- // Start the I/O thread, and save the thread handle.
- ConnData->IOThreadHandle =
- CreateThread(NULL,
- 0,
- (LPTHREAD_START_ROUTINE)IOThreadFunc,
- ConnData,
- 0,
- &ThreadId);
- if (ConnData->IOThreadHandle == NULL) {
- ChatSysError("CreateThread()",
- "HandleAcceptMessage()",
- TRUE);
- }
-
- return;
-
- Fail:
-
- DestroyWindow(ConnectionWindow);
- return;
-
- } // HandleAcceptMessage()
-
-
-
-
-
- void
- HandleConnectMessage(
- IN HWND ConnectionWindow,
- IN LPARAM LParam)
- /*++
-
- Routine Description:
-
- Handles the reception of a USMSG_CONNECT message, which indicates
- a connection attempt is complete (though not necessarily
- successful).
-
- Implementation:
-
- As with HandleAcceptMessages, this function initializes
- connection-specific data, calls WSAEventSelect to register
- interest in certain network events, and starts a network event
- handling thread.
-
- Arguments:
-
- ConnectionWindow -- Handle to the connection window associated
- with this connection request.
-
- LParam -- Contains the LParam that was a parameter of the
- USMSG_CONNECT message.
-
- Return Value:
-
- None.
-
- --*/
- {
-
- PCONNDATA ConnData; // connection-specific data
- char TitleText[TITLE_LEN]; // text buffer for window title
- DWORD ThreadId; // needed for CreateThread()
- int Error; // holds error codes
-
- Error = WSAGETSELECTERROR(LParam);
-
- // Check to see if there was an error on the connection attempt.
- if (Error) {
- char textBuf[80];
- sprintf(textBuf, "Connect error code: %x", Error);
- MessageBox(NULL, textBuf, NULL, MB_OK);
-
- // Some kind of error occurred.
- if (Error == WSAECONNREFUSED) {
-
- MessageBox(ConnectionWindow,
- "Your connection attempt has been refused",
- "Connection Refused",
- MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
- } else {
-
- MessageBox(ConnectionWindow,
- "Couldn't connect",
- "Error",
- MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
- }
-
- goto Fail;
-
- }
-
- // Connection has been accepted. Change the title of the
- // connection window to reflect who the user has connected to
- ConnData = GetConnData(ConnectionWindow);
-
- if (ConnData->CalleeBuffer.len != 0) {
-
- // The callee buffer contains the connection-time data
- // sent by the callee. -- a string containing the name of
- // the callee.
- wsprintf(TitleText, "Connected To: %s @ %s",
- ConnData->CalleeBuffer.buf, ConnData->PeerAddress);
- } else {
-
- // ConnData->PeerAddress just contains the address that
- // the user typed in before the connection attempt.
- wsprintf(TitleText, "Connected To: %s", ConnData->PeerAddress);
- }
- SetWindowText(ConnectionWindow, TitleText);
-
- WSAAsyncSelect(ConnData->Socket,
- GlobalFrameWindow,
- 0,
- 0);
-
- // Put Connection in Event Object Notification Mode.
- WSAEventSelect(ConnData->Socket,
- ConnData->SocketEventObject,
- FD_READ | FD_WRITE | FD_CLOSE);
-
- // Determine the maximum message size, if any.
- if (!GetMaxMsgSize(ConnData)) {
- goto Fail;
- }
-
- // Start the I/O thread, and save the thread handle.
- ConnData->IOThreadHandle =
- CreateThread(NULL,
- 0,
- (LPTHREAD_START_ROUTINE)IOThreadFunc,
- ConnData,
- 0,
- &ThreadId);
- if (ConnData->IOThreadHandle == NULL) {
- ChatSysError("CreateThread()",
- "HandleConnectMessage()",
- TRUE);
- }
-
- return;
-
- Fail:
-
- DestroyWindow(ConnectionWindow);
- return;
-
- } // HandleConnectMessage()
-
-
-
-
-
- BOOL
- GetMaxMsgSize(
- IN OUT PCONNDATA ConnData)
- /*++
-
- Routine Description:
-
- Determines the maximum message size (if any) of a connected
- socket. The connection must already be established, i.e. the
- socket must be bound to a local address, for this function to
- work. Fills the correct value into a field of the
- connection-specific data.
-
- Arguments:
-
- ConnData -- Connection data for a connected socket.
-
- Return Value:
-
- TRUE -- The maximum message size was succesfully determined and
- stored in ConnData->MaxMsgSize.
-
- FALSE -- There was an error calling getsockopt to get the maximum
- message size.
-
- --*/
- {
- BOOL ReturnValue = TRUE; // return value
- int DwordLen = sizeof(DWORD); // sizeof a DWORD!
- int Error; // return value of getsockopt
-
- if ((ConnData->ProtocolInfo->dwMessageSize == 0) ||
- (ConnData->ProtocolInfo->dwMessageSize == 0xffffffff)) {
-
- // Either the protocol isn't message-oriented, or there is no
- // maximum message size.
- ConnData->MaxMsgSize = NO_MAX_MSG_SIZE;
-
- } else {
-
- // There is a maximum message size. Note it.
- if (ConnData->MaxMsgSize == 0x1) {
-
- // The actual maximum message size was not stored in the
- // protocol information structure -- rather, we need to
- // get it using getsockopt().
- Error = getsockopt(ConnData->Socket,
- SOL_SOCKET,
- SO_MAX_MSG_SIZE,
- (char *)&ConnData->MaxMsgSize,
- &DwordLen);
- if (Error) {
- ReturnValue = FALSE;
- }
-
- } // if (ConnData->MaxMsgSize == 0x1)
- else {
-
- // The message size is stored in the protocol information
- // structure. Use it.
- ConnData->MaxMsgSize = ConnData->ProtocolInfo->dwMessageSize;
- }
-
-
- } // else
-
- return(ReturnValue);
-
- } // GetMaxMsgSize()
-
-
-
-
-
- BOOL
- IsSendable(
- char Char)
- /*++
-
- Routine Description:
-
- Determines whether a certain character value is ok to send over
- the socket to the far end. Eliminates most non-printable
- characters except for newline and backspace.
-
- Arguments:
-
- Char -- Supplies the character to be tested.
-
- Return Value:
-
- TRUE -- The character should be sent as is.
-
- FALSE -- The character should not be sent.
-
- --*/
- {
-
- if (isprint(Char) || (Char == '\b') ||
- (Char == '\r') || (Char == '\t') ||
- (Char == '\n') ){
- return(TRUE);
- } else {
- return(FALSE);
- }
-
- } // IsSendable()
-
-
-
-
-
- int
- DoRecv(
- IN PCONNDATA ConnData)
-
- /*++
-
- Routine Description:
-
- Receives as much available data as possible up to the size of the
- receive buffer-1 (BUFFER_LENGTH-1). A single byte is reserved at
- the end of the receive buffer to append a terminating NULL.
-
- Arguments:
-
- ConnData -- Points to the data for the connection that is ready to
- receive data.
-
- Return Value:
-
- CHAT_OK -- Received data was successfully sent to the receive edit
- control.
-
- CHAT_ERROR -- Error receiving data.
-
- CHAT_CLOSED -- The socket was gracefully closed.
-
- --*/
-
- {
- DWORD NumBytes; // stores how many bytes we received
- int Error; // gets error values
- int Result; // gets return value from WSARecv
- char Buf[BUFFER_LENGTH]; // buffer to receive data
- int ReturnValue = CHAT_OK; // returnValue
- WSABUF RecvBuffer; // WSABuf to pass to WSARecv
- DWORD Flags; // flags for WSARecv
-
- RecvBuffer.buf = Buf;
- RecvBuffer.len = BUFFER_LENGTH - 1;
-
- {
- int socket_type;
-
- socket_type = ConnData->ProtocolInfo->iSocketType;
- if ((socket_type == SOCK_DGRAM) ||
- (socket_type == SOCK_RDM) ||
- (socket_type == SOCK_SEQPACKET)) {
- Flags = MSG_PARTIAL;
- // Allow message-oriented delivery to be received within
- // our preferred buffer length without losing the trailing
- // part of longer messages.
- }
- else {
- Flags = 0;
- // The MSG_PARTIAL flag is not required and may not be
- // allowed for stream-oriented protocols.
- }
- }
-
- // Do the receive
- Result = WSARecv(ConnData->Socket,
- &RecvBuffer,
- 1,
- &NumBytes,
- &Flags,
- NULL,
- NULL);
-
- // Check for errors.
- if (Result == SOCKET_ERROR) {
-
- Error = WSAGetLastError();
-
- switch (Error) {
-
- case WSAENETRESET: // flow through
- case WSAECONNRESET:
-
- // The remote party has reset the connection.
- ReturnValue = CHAT_CLOSED;
- goto Done;
-
- case WSAEWOULDBLOCK:
-
- // No data received; return to wait for another read event.
- ReturnValue = CHAT_OK;
-
- default:
-
- // Some other error...hit the panic button.
- ReturnValue = CHAT_ERROR;
- goto Done;
- }
-
- }
-
- // Append a NULL to the text buffer.
- RecvBuffer.buf[NumBytes] = '\0';
-
- // Output the received text into the receive edit control.
- OutputString(ConnData->RecvWindow, RecvBuffer.buf);
-
- Done:
- return(ReturnValue);
-
- } // DoRecv()
-
-
-
-
-
- int
- DoOverlappedCallbackSend(
- IN POUTPUT_REQUEST OutReq,
- IN PCONNDATA ConnData)
-
- /*++
-
- Routine Description:
-
- Sends a buffer of data over a connected socket using overlapped
- I/O with callback function completion notification.
-
- Implementation:
-
- This function just does an overlapped send, giving WinSock 2 a
- completion function which will be called when the operation has
- finished, and within which cleanup will occur.
-
- Arguments:
-
- OutReq -- Points to a OUTPUT_REQUEST structure, which specifies an
- output request.
-
- ConnData -- Supplies a pointer to a CONNDATA structure, which
- identifies a Chat connection.
-
- Return Value:
-
- CHAT_WOULD_BLOCK -- The send operation failed with WSAEWOULDBLOCK.
-
- CHAT_ERROR -- A unexpected error occurred.
-
- CHAT_OK -- The send was successfully initiated. WinSock 2 will
- execute the callback function when the send has completed.
-
- --*/
-
- {
- int Size = 0; // how many bytes we send
- int Error; // return value of WSASend
- int Errno; // result of WSAGetLastError
- LPWSABUF Buffers; // points to an array of WSABUFs
- DWORD BytesSent; // needed in WSASend
- int ReturnValue; // the return value
-
- ReturnValue = CHAT_OK;
-
- // Allocate an OVERLAPPED structure.
- OutReq->Overlapped = (LPWSAOVERLAPPED)malloc(sizeof(WSAOVERLAPPED));
- if (OutReq->Overlapped == NULL) {
- ChatSysError("malloc()",
- "DoOverlappedCallbackSend()",
- TRUE);
- }
- Buffers = &OutReq->Buffer;
-
- // The hEvent field of the Overlapped structure is not used
- // for callback notification...thus we can use it any way we
- // want to pass information to the callback routine. We use
- // it to store a pointer to the OutReq associated with this
- // overlapped send operation, so the callback function can
- // free the memory.
- OutReq->Overlapped->hEvent = (WSAEVENT)OutReq;
-
- Error = WSASend(ConnData->Socket,
- Buffers,
- 1,
- &BytesSent,
- 0,
- OutReq->Overlapped,
- SendCompFunc);
-
- if (Error == SOCKET_ERROR) {
-
- // There is an error...
- Errno = WSAGetLastError();
- if (Errno == WSAEWOULDBLOCK) {
-
- // WSAEWOULDBLOCK means we have to wait for an FD_WRITE
- // before we can send.
- ConnData->WriteOk = FALSE;
- ReturnValue = CHAT_WOULD_BLOCK;
-
- } else if (Errno == WSA_IO_PENDING) {
-
- // Overlapped send successfully initiated.
- ReturnValue = CHAT_OK;
- }
- else {
-
- // An unexpected error occurred.
- ReturnValue = CHAT_ERROR;
- }
-
- }
-
- // No error -- the I/O request was completed immediately...
- return(ReturnValue);
-
- } // DoOverlappedCallbackSend()
-
-
-
-
-
- int
- DoOverlappedEventSend(
- IN POUTPUT_REQUEST OutReq,
- IN PCONNDATA ConnData)
-
- /*++
-
- Routine Description:
-
- Sends a buffer of data over a connected socket using overlapped
- I/O with event notification.
-
- Implementation:
-
- If the overlapped send is succesfully initiated, this function
- increases the event count and adds an entry to the event array of
- the associated connection. During IOThreadFunc, the thread will
- thus wait on the new event as well, and will perform the
- appropriate cleanup action when awoken.
-
- Arguments:
-
- OutReq -- Points to a OUTPUT_REQUEST structure, which specifies an
- output request.
-
- ConnData -- Supplies a pointer to a CONNDATA structure, which
- identifies a Chat connection.
-
- Return Value:
-
- CHAT_WOULD_BLOCK -- The send operation failed with WSAEWOULDBLOCK.
-
- CHAT_ERROR -- A unexpected error occurred.
-
- CHAT_OK -- The send was successfully initiated and the new event
- placed in the event array; it will be signaled by WinSock 2 when
- the send operation has completed.
-
- --*/
-
- {
- int Size = 0; // how many bytes we send
- int Error; // return value of WSASend
- int Errno; // result of WSAGetLastError
- LPWSABUF Buffers; // points to an array of WSABUFs
- DWORD BytesSent; // needed in WSASend
- int ReturnValue; // the return value
-
- ReturnValue = CHAT_OK;
-
- // Allocate an OVERLAPPED structure.
-
- // Note that the pointer to an overlapped structure is kept in
- // OutReq. We use an array of OutReq pointers that is parallel to
- // the event array. With that one pointer, then, we can find the
- // associated Overlapped structure and free it, and then free the
- // OutReq structure itself.
- OutReq->Overlapped = (LPWSAOVERLAPPED)malloc(sizeof(WSAOVERLAPPED));
- if (OutReq->Overlapped == NULL) {
- ChatSysError("malloc()",
- "DoOverlappedEventSend()",
- TRUE);
- }
- Buffers = &OutReq->Buffer;
-
- OutReq->Overlapped->hEvent =
- (WSAEVENT)CreateEvent(NULL,
- FALSE,
- FALSE,
- NULL);
- if (OutReq->Overlapped->hEvent == NULL) {
- ChatSysError("CreateEvent()",
- "DoOverlappedEventSend()",
- TRUE);
- }
-
- // Do the send.
- Error = WSASend(ConnData->Socket,
- Buffers,
- 1,
- &BytesSent,
- 0,
- OutReq->Overlapped,
- NULL);
-
- if (Error == SOCKET_ERROR) {
-
- // There is an error...
- Errno = WSAGetLastError();
- if (Errno == WSAEWOULDBLOCK) {
-
- // WSAEWOULDBLOCK means we have to wait for an FD_WRITE
- // before we can send.
- ConnData->WriteOk = FALSE;
- ReturnValue = CHAT_WOULD_BLOCK;
-
- } else if (Errno == WSA_IO_PENDING) {
-
- // Overlapped send successfully initiated.
- // Increase the event count, and update the event and
- // output request arrays to hold the entries for this
- // overlapped send.
- ConnData->NumEvents++;
- if (ConnData->NumEvents > WSA_MAXIMUM_WAIT_EVENTS) {
-
- // We're trying to wait on too many events at
- // once. It's very unlikely this could happen --
- // you'd have to get about 62 overlapped sends, in
- // row, before one of them is completed and
- // signaled. So just return CHAT_ERROR which will
- // break the connection.
- ReturnValue = CHAT_ERROR;
-
- } else {
-
- ConnData->EventArray[ConnData->NumEvents - 1] =
- OutReq->Overlapped->hEvent;
-
- ConnData->OutReqArray[ConnData->NumEvents - 1] = OutReq;
- ReturnValue = CHAT_OK;
- }
- } // else if (...)
- else {
-
- // An unexpected error occurred.
- ReturnValue = CHAT_ERROR;
- }
-
- } // if (Error == SOCKET_ERROR)
-
- // No error -- the I/O request was completed immediately...
- ReturnValue = CHAT_OK;
-
- return(ReturnValue);
-
- } // DoOverlappedEventSend()
-
-
-
-
-
- int
- DoSend(
- IN POUTPUT_REQUEST OutReq,
- IN PCONNDATA ConnData)
-
- /*++
-
- Routine Description:
-
- Sends a buffer of data over a connected socket.
-
- Implementation:
-
- This function uses the information contained in the output request
- structure to determine whether to use overlapped or non-overlapped
- I/O. If using overlapped I/O, it calls an appropriate function
- depending on whether the symbol CALLBACK_NOTIFICATION has been
- defined. Otherwise, the non-overlapped send in performed
- immediately.
-
- Arguments:
-
- OutReq -- Points to a OUTPUT_REQUEST structure, which specifies an
- output request.
-
- ConnData -- Supplies a pointer to a CONNDATA structure, which
- identifies a Chat connection.
-
- Return Value:
-
- CHAT_WOULD_BLOCK -- The send operation failed with WSAEWOULDBLOCK.
-
- CHAT_ERROR -- A unexpected error occurred.
-
- CHAT_OK -- The send was successfully initiated. If the send was
- overlapped, either a callback function is forthcoming or another
- event was placed in the ConnData->EventArray for IOThreadFunc to
- wait on until it's signaled by WinSock 2.
-
- --*/
-
- {
- int Size = 0; // how many bytes we send
- int Error; // return value of WSASend
- int Errno; // result of WSAGetLastError
- WSABUF Buffers[1]; // points to the data to be sent
- DWORD BytesSent; // needed in WSASend
- int ReturnValue; // the return value
-
- if (OutReq->Type == NON_OVERLAPPED_IO) {
-
- // Do a non-overlapped send by setting lpOverlapped and
- // lpCompletionRoutine to NULL.
- Buffers[0].len = OutReq->Buffer.len;
- Buffers[0].buf = OutReq->Buffer.buf;
- Error = WSASend(ConnData->Socket,
- Buffers,
- 1,
- &BytesSent,
- 0,
- NULL,
- NULL);
-
- if (Error == SOCKET_ERROR) {
-
- // There's an error...
- Errno = WSAGetLastError();
- if (Errno == WSAEWOULDBLOCK) {
-
- // WSAEWOULDBLOCK means we have to wait for an FD_WRITE
- // before we can send.
- ConnData->WriteOk = FALSE;
- ReturnValue = CHAT_WOULD_BLOCK;
-
- } else {
-
- // It's an unexpected error.
- ReturnValue = CHAT_ERROR;
- }
- } else {
-
- // There's no error.
- ReturnValue = CHAT_OK;
- free(OutReq);
- }
-
- } else if (OutReq->Type == OVERLAPPED_IO) {
-
- #ifdef CALLBACK_NOTIFICATION
-
- ReturnValue = DoOverlappedCallbackSend(OutReq, ConnData);
-
- #else
-
- ReturnValue = DoOverlappedEventSend(OutReq, ConnData);
-
- #endif
-
- } else {
-
- // Unknown output type...
- MessageBox(ConnData->ConnectionWindow,
- "Unknown output type given to IOThread. Aborting.",
- "Error.", MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
- ReturnValue = CHAT_ERROR;
- }
-
- return(ReturnValue);
-
- } // DoSend()
-
-
-
-
-
- void CALLBACK
- SendCompFunc(
- IN DWORD Error,
- IN DWORD BytesTransferred,
- IN LPWSAOVERLAPPED Overlapped,
- IN DWORD Flags)
- /*++
-
- Routine Description:
-
- Completion routine called after a successfully initiated overlapped
- send operation completes; cleans up data structures associated
- with the send.
-
- Arguments:
-
- Error -- Supplies the completion status for the overlapped
- operation.
-
- BytesTransferred -- Supplies the actual number of bytes sent.
-
- Overlapped -- Supplies a pointer to a WSAOVERLAPPED structure.
- The hEvent field in the structure contains a pointer to the
- OUTPUT_REQUEST structure associated with this send operation.
-
- Flags -- Not yet used.
-
- Return Value:
-
- None
-
- --*/
-
- {
- POUTPUT_REQUEST OutReq; // The output request
-
- OutReq = (POUTPUT_REQUEST)(Overlapped->hEvent);
-
- if (Error) {
- MessageBox(NULL,
- "Error during overlapped send.",
- "Error",
- MB_OK | MB_SETFOREGROUND);
- }
-
- // Free the data buffer, the output request structure, and the
- // overlapped I/O structure.
- free(OutReq->Buffer.buf);
- free(OutReq);
- free(Overlapped);
-
- } // SendCompFunc()
-
-
-
-
-
- PCONNDATA
- GetConnData(
- IN HWND ConnectionWindow
- )
-
- /*++
-
- Routine Description:
-
- Retrieves a pointer to the PCONNDATA data structure associated
- with a connection window
-
- Arguments:
-
- ConnectionWindow - Supplies the handle to a connection window.
-
- Return Value:
-
- Returns the PCONNDATA associated with the given connection window
- handle.
-
- --*/
-
- {
- return((PCONNDATA)GetWindowLong(ConnectionWindow, GWL_CONNINFO));
-
- } // GetConnData()
-
-
-
-
-
- BOOL
- MakeConnection(
- IN HWND ConnectionWindow)
-
- /* ++
-
- Routine Description:
-
- Initiates a call to another instance of chat.
- 1) Creates a socket
- 2) Set the socket up for windows message notification of FD_CONNECT
- events.
- 3) Allocate a buffer for caller name & subject, and fill it in.
- 4) Allocate a buffer to receive callee name.
- 5) Set up quality of service for the connection.
- 6) Attempt a connection
-
- Arguments:
-
- ConnectionWindow - Handle to the window that receives
- notification when an FD_CONNECT event occurs.
-
- Return Value:
-
- TRUE - A connection attempt was successfully initiated.
-
- FALSE - Error occurred while attempting to initiate a connection.
-
- --*/
-
- {
- int ConnectStatus; // the return value of WSAConnect
- int Error; // gets error values
- BOOL ReturnValue; // holds the return value
- PCONNDATA ConnData; // connection-specific data
- LPWSABUF CallerBuffer; // user data we will send
- LPWSABUF CalleeBuffer; // user data we will receive
- QOS QualityOfService; // QOS structure, used by WSAConnect
- LPFLOWSPEC FlowSpec; // dummy pointer for code readability
- char MsgText[MSG_LEN]; // holds message strings
- BOOL QOSSupported; // does the protocol support QOS?
- BOOL CTDTSupported; // support for conn-time data xfer?
- struct sockaddr *SockAddr; // socket address for WSAConnect
- int SockAddrLen; // the length of the above
-
-
- ReturnValue = TRUE;
- ConnData = GetConnData(ConnectionWindow);
- QOSSupported = (ConnData->ProtocolInfo->dwServiceFlags1 &
- XP1_QOS_SUPPORTED);
- CTDTSupported = (ConnData->ProtocolInfo->dwServiceFlags1 &
- XP1_CONNECT_DATA);
- if (CTDTSupported) {
-
- // CallerBuffer and CallerBuffer->buf (allocated within the
- // NameAndSubject dialog box procedure) both get freed by the
- // end of this function. CalleeBuffer.buf gets freed upon
- // connection shutdown -- it needs to be valid after this
- // function has exited.
- CallerBuffer = (LPWSABUF)malloc(sizeof(WSABUF));
- if (CallerBuffer == NULL) {
- ChatSysError("malloc()",
- "MakeConnection()",
- TRUE);
- }
- CalleeBuffer = &ConnData->CalleeBuffer;
-
- // The connection-time data sent back when/if this connection
- // is accepted will just contain the callee's name.
- CalleeBuffer->len = NAME_LEN + 1;
- CalleeBuffer->buf = (char *)malloc(CalleeBuffer->len);
- if (CallerBuffer->buf == NULL) {
- ChatSysError("malloc()",
- "MakeConnection()",
- TRUE);
- }
-
- // Prompt the user for his name and the subject of the call.
- // a pointer to the CallerBuffer is passed to the dialog box
- // procedure and the data is packed into this memory.
- if (!DialogBoxParam(GlobalInstance,
- "NameAndSubjectDlg",
- ConnectionWindow,
- NameAndSubjectDlgProc,
- (LPARAM)CallerBuffer)) {
- ReturnValue = FALSE;
- goto Done;
- }
- } // if (CTDTSupported)
-
- // Create a socket for this connection.
- ConnData->Socket = WSASocket(FROM_PROTOCOL_INFO,
- FROM_PROTOCOL_INFO,
- FROM_PROTOCOL_INFO,
- ConnData->ProtocolInfo,
- 0,
- WSA_FLAG_OVERLAPPED);
-
- if (ConnData->Socket == INVALID_SOCKET) {
-
- MessageBox(ConnectionWindow, "Could not open a socket.", "Error",
- MB_OK | MB_SETFOREGROUND);
- ReturnValue = FALSE;
- goto Done;
-
- } else {
-
- // Set up socket for windows message event notification.
- WSAAsyncSelect(ConnData->Socket,
- ConnectionWindow,
- USMSG_CONNECT,
- FD_CONNECT);
- }
-
- if (QOSSupported) {
-
- // Set up quality of service info we want. Do not include any
- // provider-specific information.
- QualityOfService.ProviderSpecific.len = 0;
- QualityOfService.ProviderSpecific.buf = NULL;
-
- // FlowSpec is used only to make this code more readable.
- FlowSpec = & QualityOfService.SendingFlowspec;
- FlowSpec->TokenRate = TOKENRATE;
- FlowSpec->TokenBucketSize = QOS_UNSPECIFIED;
- FlowSpec->PeakBandwidth = QOS_UNSPECIFIED;
- FlowSpec->Latency = QOS_UNSPECIFIED;
- FlowSpec->DelayVariation = QOS_UNSPECIFIED;
- FlowSpec->ServiceType = SERVICETYPE_BESTEFFORT;
-
- // again, the extra FlowSpec variable is for readability
- FlowSpec = & QualityOfService.ReceivingFlowspec;
- FlowSpec->TokenRate = TOKENRATE;
- FlowSpec->TokenBucketSize = QOS_UNSPECIFIED;
- FlowSpec->PeakBandwidth = QOS_UNSPECIFIED;
- FlowSpec->Latency = QOS_UNSPECIFIED;
- FlowSpec->DelayVariation = QOS_UNSPECIFIED;
- FlowSpec->ServiceType = SERVICETYPE_BESTEFFORT;
- }
-
- // Reminder: WinSock 2 requires that we pass a struct sockaddr *
- // to WSAConnect; however, the service provider is free to
- // interpret the pointer as an arbitrary chunk of data of size
- // SockAddrLen.
- SockAddr = (struct sockaddr *)ConnData->RemoteSockAddr.buf;
- SockAddrLen = ConnData->RemoteSockAddr.len;
-
-
- // Try to connect; depending on whether QOS or Connection Time
- // Data Transfer are supported, pass the appropriate data.
- if (QOSSupported && CTDTSupported) {
-
- // Both are supported...
- ConnectStatus = WSAConnect(ConnData->Socket,
- SockAddr,
- SockAddrLen,
- CallerBuffer,
- CalleeBuffer,
- &QualityOfService,
- NULL);
- } else if (!QOSSupported && CTDTSupported) {
-
- // Only CTDT is supported...
- ConnectStatus = WSAConnect(ConnData->Socket,
- SockAddr,
- SockAddrLen,
- CallerBuffer,
- CalleeBuffer,
- NULL,
- NULL);
-
- } else if (QOSSupported && !CTDTSupported) {
- // Only QOS is supported... case for ATM
- ConnectStatus = WSAConnect(ConnData->Socket,
- SockAddr,
- SockAddrLen,
- NULL,
- NULL,
- &QualityOfService,
- NULL);
- } else {
-
- // Neither is supported... case for TCP
- ConnectStatus = WSAConnect(ConnData->Socket,
- SockAddr,
- SockAddrLen,
- NULL,
- NULL,
- NULL,
- NULL);
- }
-
- // Check for errors.
- if (ConnectStatus == SOCKET_ERROR) {
- Error = WSAGetLastError();
- if (Error != WSAEWOULDBLOCK) {
- wsprintf(MsgText, "WSAConnect failed. Error code: %d",
- Error);
- MessageBox(ConnectionWindow, MsgText, "Error",
- MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
- ReturnValue = FALSE;
- }
- } else {
- MessageBox(ConnectionWindow,
- "WSAConnect should have returned SOCKET_ERROR.",
- "Error", MB_OK | MB_ICONSTOP | MB_SETFOREGROUND);
- ReturnValue = FALSE;
- }
-
- Done:
- // Free allocated memory, except CalleeBuffer which will be
- // freed when connection window is destroyed.
- if (CTDTSupported) {
- free(CallerBuffer->buf);
- free(CallerBuffer);
- }
- return(ReturnValue);
- } // MakeConnection()
-
-
-
-
-
- BOOL
- FillInFamilies(
- IN HWND DialogWindow,
- IN DWORD FamilyLB)
- /*++
-
- Routine Description:
-
- Fills in the listbox with a string for each protocol on which Chat
- has a listening socket.
-
- Implementation:
-
- For each socket in the ListeningSockets array, this function:
-
- 1. Gets the associated protocol information structure.
-
- 2. If Chat recognizes the address family, it prints it in a
- string; if not, it prints "unknown".
-
- 3. In the second half of the string, prints out the
- human-readable string contained in the protocol information.
-
- 4. Sends the string to be an entry in the listbox identified
- by FamilyLB.
-
- Arguments:
-
- DialogWindow -- Window handle for the dialog box.
-
- FamilyLB -- Integer identifier for a listbox in the dialog box.
-
- Return Value:
-
- TRUE - All messages were successfully sent to the listbox.
-
- FALSE - An LB_ADDSTRING message failed.
-
- --*/
-
- {
-
- int i; // counting variable
- LRESULT Result; // result of SendMessage calls
- char LBString[MSG_LEN]; // string to send to the listbox
- int Offset; // index into the string
-
- // Iterate through all members of the ListeningSockets array.
- for (i = 0; i < NumFound; i++){
-
- // We are prepending a number to the list box string to be displayed
- // since the list box does us the favor of alphabetizing the
- // the sting and we are depending on the list entries appearing in the
- // list box in the order that we added them to the list.
-
- Offset = wsprintf(LBString, "%02i ",i);
-
- switch (ListeningSockets[i].ProtocolInfo->iAddressFamily) {
-
- case AF_INET:
-
- Offset += wsprintf(LBString+Offset, "INET/");
- wsprintf(LBString + Offset, "%s",
- ListeningSockets[i].ProtocolInfo->szProtocol);
- Result = SendMessage(GetDlgItem(DialogWindow, FamilyLB),
- LB_ADDSTRING, 0, (LPARAM)LBString);
- break;
-
- case AF_ATM:
- Offset += wsprintf(LBString+Offset, "ATM/");
- wsprintf(LBString + Offset, "%s",
- ListeningSockets[i].ProtocolInfo->szProtocol);
- Result = SendMessage(GetDlgItem(DialogWindow, FamilyLB),
- LB_ADDSTRING, 0, (LPARAM)LBString);
- break;
-
- case AF_IPX:
- Offset += wsprintf(LBString+Offset, "IPX/");
- wsprintf(LBString + Offset, "%s",
- ListeningSockets[i].ProtocolInfo->szProtocol);
- Result = SendMessage(GetDlgItem(DialogWindow, FamilyLB),
- LB_ADDSTRING, 0, (LPARAM)LBString);
- break;
-
- case AF_NETBIOS:
- Offset += wsprintf(LBString+Offset, "NETBIOS/");
- wsprintf(LBString + Offset, "%s",
- ListeningSockets[i].ProtocolInfo->szProtocol);
- Result = SendMessage(GetDlgItem(DialogWindow, FamilyLB),
- LB_ADDSTRING, 0, (LPARAM)LBString);
- break;
- default:
-
- Offset += wsprintf(LBString+ Offset, "(unknown)/");
- wsprintf(LBString + Offset, "%s",
- ListeningSockets[i].ProtocolInfo->szProtocol);
- Result = SendMessage(GetDlgItem(DialogWindow, FamilyLB),
- LB_ADDSTRING, 0, (LPARAM)LBString);
- break;
-
- }
- if ((Result == LB_ERR) || (Result == LB_ERRSPACE)) {
- return(FALSE);
- }
- }
- return(TRUE);
-
- } // FillInFamilies()
-
-
-
-
-
- LPWSAPROTOCOL_INFO
- GetProtoFromIndex(
- IN int LBIndex)
- /*++
-
- Routine Description:
-
- Takes an index into the ChooseFamily dialog box and returns the
- protocol associated with that index. This works because when the
- dialog box is set up, the strings representing the protocols are
- added to the listbox in the order they fall in ListeningSockets.
-
- Arguments:
-
- LBIndex -- The index of the user's selection.
-
- Return Value:
-
- NULL -- The index doesn't correspond to an element in the
- ListeningSockets array.
-
- LPWSAPROTOCOL_INFO -- A pointer to the protocol information struct
- corresponding to LBIndex.
-
- --*/
- {
- if (LBIndex > (NumFound - 1)) {
- return(NULL);
- }
- return(ListeningSockets[LBIndex].ProtocolInfo);
-
- } // GetProtoFromIndex()
-
-
-
-
-
- LPWSAPROTOCOL_INFO
- GetProtoFromSocket(
- IN SOCKET Socket)
- /*++
-
- Routine Description:
-
- Searches the ListeningSockets array for the first entry with a
- Socket field equal to the Socket parameter. When found, it
- returns a pointer to the associated protocol information
- structure. If not found, return NULL.
-
- Arguments:
-
- Socket -- The socket who's associated WSAPROTOCOL_INFO struct we are
- looking for.
-
- Return Value:
-
- NULL -- The socket was not found in the ListeningSockets array.
-
- LPWSAPROTOCOL_INFO -- A pointer to the protocol information struct
- for the socket.
-
- --*/
- {
-
- int i; // counting variable
-
- for (i = 0; i < NumFound; i++) {
- if (ListeningSockets[i].Socket == Socket) {
- return(ListeningSockets[i].ProtocolInfo);
- }
- }
- return(NULL);
-
- } // GetProtoFromSocket()
-
-
-
-
-
- void
- CleanupConnection(
- IN PCONNDATA ConnData)
- /*++
-
- Routine Description:
-
- Frees all memory and objects allocated for this connection.
-
- Arguments:
-
- ConnData -- Pointer to the connection-specific data structure.
-
- Return Value:
-
- None.
-
- --*/
- {
-
- // Clean up connection-specific data. To keep this code
- // readable, we ignore any errors.
- if (ConnData->SocketEventObject != NULL) {
- CloseHandle(ConnData->SocketEventObject);
- ConnData->SocketEventObject = NULL;
- }
- if (ConnData->OutputEventObject != NULL) {
- CloseHandle(ConnData->OutputEventObject);
- ConnData->OutputEventObject = NULL;
- }
- if (ConnData->OutputQueue != NULL) {
- QFree(ConnData->OutputQueue);
- ConnData->OutputQueue = NULL;
- }
- if (ConnData->IOThreadHandle != NULL) {
- CloseHandle(ConnData->IOThreadHandle);
- ConnData->IOThreadHandle = NULL;
- }
- if (ConnData->Socket != INVALID_SOCKET) {
- closesocket(ConnData->Socket);
- }
- if (ConnData->RemoteSockAddr.buf != NULL) {
- free(ConnData->RemoteSockAddr.buf);
- ConnData->RemoteSockAddr.buf = NULL;
- }
- if (ConnData->CalleeBuffer.buf != NULL) {
- free(ConnData->CalleeBuffer.buf);
- ConnData->CalleeBuffer.buf = NULL;
- }
- free(ConnData);
-
- } // CleanupConnection()
-